package com.mew.slots.core.common.game;


import com.mew.common.util.TxtUtils;
import com.mew.slots.core.common.game.vo.BasePlayMsgs;
import com.mew.slots.core.common.roller.ili.InRoom;
import com.mew.slots.core.common.roller.ili.xml.IliXml;
import com.mew.slots.core.common.roller.xml.BaseXml;
import lombok.Data;
import lombok.ToString;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.function.IntFunction;

@Data
@ToString
public class BaseRoom {

	/*
	 * 构造传进来的
	 */
	public int row;
	public int col;
	public boolean free;
	public int rollerID;
	public int controlType;
	public InRoom in;


	/**
	 * 自己赋值的
	 */
	public BasePlayMsgs res;
	public IliXml iliXml;
	public BaseXml rollerXml;
	public int _WILD = -1;
	public ArrayList<Integer> spes;//_WILD不允许替换
	public int[][] rate;
	public int[][] lines;
	public int[][] alllines;

	/**
	 * 后面会处理的
	 */
	public int[] endSlots;
	public int[][] iconLines;
	public HashSet<Integer> uvSet = new HashSet<>();

	/**
	 * 分散夺宝
	 * @return
	 */
	public int fsdb(int type) {
		int num=0;
		for(int icon:endSlots){
			if(icon==type){
				num++;
			}
		}
		return num;
	}

	/**
	 * 线上左连续
	 * @return
	 */
	public int xszlx(int type){
		int max = 0;
		int time;
		for (int[] iconLine : iconLines) {
			time = 0;
			for (int i : iconLine) {
				if (i==type){
					time++;
				}else {
					max = max>time?max:time;
					break;
				}
			}
		}

		return max;
	}

	/**
	 * 连续几列连续
	 * @param type 类型
	 * @return
	 */
	public int lxllx(int type){
		int max = 0;
		int time = 0;
		for (int i = 0; i < col; i++) {
			if (llx(type,i)){
				time++;
				max = max>time?max:time;
			}else {
				time=0;
			}
		}

		return max;
	}

	/**
	 * 左连续几列连续
	 * @param type 类型
	 * @return
	 */
	public int zlxllx(int type){
		int time = 0;
		for (int i = 0; i < col; i++) {
			if (llx(type,i)){
				time++;
			}else{
				break;
			}
		}
		return time++;
	}

	/**
	 * 线上连续
	 * @param type 类型
	 * @return
	 */
	public int xslx(int type){

		int max = 0;
		int time;
		for (int[] iconLine : iconLines) {
			time = 0;
			for (int i : iconLine) {
				if (i==type){
					time++;
					max = max>time?max:time;
				}else {
					max = max>time?max:time;
					time=0;
				}
			}
		}

		return max;
	}

	/**
	 * 固定列有图标
	 * @return
	 */
	public boolean llx(int type,int...lines){
		for(int line:lines){
			if(!rowHasIcon(line,type)){
				return false;
			}
		}
		return true;
	}

	private boolean rowHasIcon(int line,int type){
		int[] rnd=endSlots;
		for(int i=0;i<row;i++){
			if(rnd[i*col+line]==type){
				return true;
			}
		}
		return false;
	}

	/**
	 * 每条线上图标
	 */
	public void checkLine() {
		iconLines = new int[lines.length][];
		for(int i = 0 ;i<lines.length ;i++)
		{
			BasePlayMsgs.LineResult result = new BasePlayMsgs.LineResult();
			result.lineNum = i;
			int[] tpl =  lines[i];	//奖线模板
			iconLines[i] = new int[tpl.length];
			for(int j=0;j<tpl.length;j++)
			{
				iconLines[i][j] = endSlots[tpl[j]];
			}
		}
	}

	/**
	 *  每条线算分
	 *  2021/7/29 谭松林 修改：策划说一个线出现wild开始连线，就要看倍数确定 是使用wild的倍数还是图标的倍数
	 */
	public void checkaward(){

		int[] rl;
		int type;//类型
		int tNum;//类型连线数量
		int wNum;//wild连线数量

		int cType;//最终用作计算的类型
		int cRate;//最终用作计算的倍数
		int cNum;//最终用作计算的图标数量

		for (int j = 0;j< iconLines.length;j++) {
			BasePlayMsgs.LineResult bgo = new BasePlayMsgs.LineResult();
			bgo.lineNum = j;
			rl = iconLines[j].clone();
			//初始
			type = rl[0];
			tNum = 1;
			wNum = type == _WILD?1:0;
			//根据线  算出连线图标数量
			for (int i = 1; i < rl.length; i++) {
				if(type == _WILD){
					if(rl[i] == _WILD){
						wNum++;
					}else{
						type = rl[i];
						//发现类型是不用算分的特殊图标   跳出
						tNum = wNum+1;
					}
				}else{
					if(rl[i] == _WILD || rl[i] == type){
						tNum++;
					}else{
						break;
					}
				}
			}
			if(spes.contains(type)){
				break;
			}
			int typeRate = rate[type][tNum - 1];
			int wildRate = wNum > 0?rate[_WILD][wNum-1] : 0;

			if(typeRate > wildRate){
				cType = type;
				cRate = typeRate;
				cNum = tNum;
			}else{
				cType = _WILD;
				cRate = wildRate;
				cNum = wNum;
			}

			if (cRate > 0) {
				bgo.mult = cRate;
				bgo.type = cType;
				bgo.num = cNum;
				bgo.uvIdx = Arrays.stream(lines[j]).limit(cNum).toArray();
				res.lines.add(bgo);
			}
		}

		for(BasePlayMsgs.LineResult x:res.lines)
		{
			res.multiple += x.mult;
		}

	}

	public void checkLine243() {
		for (int i = 0; i < row ; i++) {
			int[] has = new int[col];
			Integer type = endSlots[col * i];
			if (!spes.contains(type)){
				HashSet<Integer> seat = new HashSet<>();
				get243(has,type,0,true,seat);
			}
		}

		for(BasePlayMsgs.LineResult x:res.lines)
		{
			res.multiple += x.mult;
		}

	}

	public void get243(int[] has,int type,int start,boolean w0,HashSet<Integer> seat){

		if (start >col-1){
			//算分
			getRes243(type,start,has,seat);
			return;
		}

		//一列几个
		int num = 0;
		for (int i = 0; i < row; i++) {
			Integer thisType = endSlots[i * col + start];
			//这个和第一个类型一样  或这个是w类型不是s
			if (thisType==type||(!w0 && thisType==_WILD && !spes.contains(type))){
				seat.add(i*col+start);
				num++;
			}
		}

		//下一列
		//又wild重来

		if (type == _WILD) {
			int[] has2 = has.clone();
			//小于5个继续
			if (start<col-1){
				has2[start] = 1;
				for (int i = 0; i < row; i++) {
					Integer t = endSlots[i * col + start + 1];
					if (spes.contains(type)){
						continue;
					}
					get243(has2,t,start+1,true, (HashSet<Integer>) seat.clone());
				}
			}else {
				//等于5个结算
				return;
			}

		}else if (w0){
			//第一把或者上一把是w
			has[start] = 1;
			get243(has, type, start+1,false,seat);
		} else  if (num>0){
			//正常
			has[start] = num;

			get243(has, type, start+1,false,seat);
		}else {
			getRes243(type,start,has,seat);
		}

	}

	public void getRes243(int type,int num,int[] has,HashSet<Integer> seat){
		if (spes.contains(type)){
			return;
		}
		Integer rate0  = rate[type][num-1];
		if (rate0>0){

			BasePlayMsgs.LineResult result = new BasePlayMsgs.LineResult();

			result.mult = 1;
			for (int i = 0; i < num; i++) {

				result.mult *= has[i];

			}

			result.mult *= rate0;

			result.type = type;

			result.num = num;

			result.uvIdx = new ArrayList<Integer>(seat).stream().mapToInt(Integer::intValue).toArray();

			res.lines.add(result);
		}
	}

	public void init(Integer rollerID, IliXml xml,Boolean free, long bet0, Integer controlType) {
		init( rollerID,  xml,  null,  free,  bet0,  controlType,  alllines.length);
	}

	public void init(Integer rollerID, IliXml xml,Boolean free, long bet0, Integer controlType, Integer lineNum) {
		init( rollerID,  xml,  null,  free,  bet0,  controlType,  lineNum);
	}

	public void init(Integer rollerID, IliXml xml,InRoom in, Boolean free, long bet0, Integer controlType) {
		init( rollerID,  xml,  in,  free,  bet0,  controlType,  alllines.length);
	}

	public void init(Integer rollerID, IliXml xml, InRoom in, Boolean free, long bet0, Integer controlType, Integer lineNum) {

		this.iliXml = xml;
		this.in = in;

		if(null!=alllines) {
			this.lines = Arrays.stream(this.alllines).limit(lineNum).toArray(new IntFunction<int[][]>() {
				@Override
				public int[][] apply(int value) {
					return new int[lineNum][];
				}
			});
		}
		//扣下注
		this.res.bet = bet0;

		this.res.allwin = 0;
		//线数
		this.res.setLine(lineNum);
		//开始主游戏
		this.free = free;
		this.rollerID = rollerID;
		this.controlType = controlType;

	}

	public void init(Integer rollerID,BaseXml xml, Boolean free, long bet0, Integer controlType) {
		init( rollerID, xml,  free,  bet0,  controlType,  alllines.length);
	}

	public void init(Integer rollerID,BaseXml xml, Boolean free, long bet0, Integer controlType, Integer lineNum) {

		this.rollerXml = xml;

		if (null!=alllines){
			this.lines = Arrays.stream(this.alllines).limit(lineNum).toArray(new IntFunction<int[][]>() {
				@Override
				public int[][] apply(int value) {
					return new int[lineNum][];
				}
			});
		}

		//扣下注
		this.res.bet = bet0;

		this.res.allwin = 0;
		//线数
		this.res.setLine(lineNum);
		//开始主游戏
		this.free = free;
		this.rollerID = rollerID;
		this.controlType = controlType;

	}

	public void initTest(int[] endSlots,int lineNum) {
		if (lineNum==0){
			this.lines = alllines;
		}else {
			this.lines = Arrays.stream(this.alllines).limit(lineNum).toArray(new IntFunction<int[][]>() {
				@Override
				public int[][] apply(int value) {
					return new int[lineNum][];
				}
			});
		}
		this.endSlots = endSlots;
		this.res.endSlots = endSlots;
		//扣下注
		this.res.bet = 0;
		this.res.allwin = 0;
		//线数
		this.res.setLine(lines.length);
		//开始主游戏
		this.free = false;
		this.rollerID = 0;
		this.controlType = 0;
	}

	/**
	 * 取线
	 */
	public void getLinesIli(){

		if (controlType>0){
			endSlots = control();
		} else {
			endSlots = getIliEndSlots();

		}
		res.endSlots = endSlots.clone();
	}

	public int[] getIliEndSlots(){
		return iliXml.getLineints(0,rollerID,in,free?1:0);
	}
	/**
	 * 取线
	 */
	public void getLinesXml(){

		if (controlType>0){
			endSlots = control();
		} else {
			endSlots = rollerXml.getLineInts( free ? 1 : 0,rollerID);
		}
		res.endSlots = endSlots.clone();
	}

	public int[] control(){
		int[] ints = new int[res.line];


		return ints;
	}

	public int[] bigwin(){
		String[] split = TxtUtils.byFile(rollerXml.bigWinPath)
				.replace("\n", "")
				.replace("\r", "")
				.replace("\t", "")
				.split(",");
		return Arrays.stream(split).mapToInt(Integer::parseInt).toArray();
	};

	/**
	 * 免费特殊
	 */
	public void freeBouns(){

	}
	public void initUvSet(){
		for (BasePlayMsgs.LineResult x : res.lines) {
			for (int uvIdx : x.uvIdx) {
				uvSet.add(uvIdx);
			}
		}
	}
	//添加uv
	public void addUv(int... indexs){
		for ( int index : indexs) {
			uvSet.add(index);
		}
	}

	public void roundPlayIli() {

		//取线
		getLinesIli();

		//九条线
		checkLine();

		//算分
		checkaward();
		//闪的图
		initUvSet();

		freeBouns();

		this.res.uv=uvSet.stream().mapToInt(Integer::intValue).toArray();

		this.res.gamewin = this.res.bet*this.res.multiple;

		this.res.allwin += this.res.gamewin+this.res.bounswin;

	}

	public void roundPlayIli243() {

		//取线
		getLinesIli();

		//243条线
		checkLine243();
		//闪的图
		initUvSet();

		freeBouns();

		this.res.uv=uvSet.stream().mapToInt(Integer::intValue).toArray();

		this.res.gamewin = this.res.bet*this.res.multiple;

		this.res.allwin += this.res.gamewin+this.res.bounswin;
	}

	public void roundPlay() {

		//取线
		getLinesXml();

		//九条线
		checkLine();

		//算分
		checkaward();
		//闪的图
		initUvSet();

		freeBouns();

		this.res.uv=uvSet.stream().mapToInt(Integer::intValue).toArray();

		this.res.gamewin = this.res.bet*this.res.multiple;

		this.res.allwin += this.res.gamewin+this.res.bounswin;
	}

	public void roundPlay243() {

		//取线
		getLinesXml();

		//243条线
		checkLine243();
		//闪的图
		initUvSet();

		freeBouns();

		this.res.uv=uvSet.stream().mapToInt(Integer::intValue).toArray();

		this.res.gamewin = this.res.bet*this.res.multiple;

		this.res.allwin += this.res.gamewin+this.res.bounswin;
	}

    public void roundPlayTest() {

        //九条线
        checkLine();
        //算分
        checkaward();
        //闪的图
        initUvSet();

        freeBouns();

        this.res.uv=uvSet.stream().mapToInt(Integer::intValue).toArray();

        this.res.gamewin = this.res.bet*this.res.multiple;

        this.res.allwin += this.res.gamewin+this.res.bounswin;
    }

    public void roundPlayTest243() {

        checkLine243();
        //闪的图
        initUvSet();

        freeBouns();

        this.res.uv=uvSet.stream().mapToInt(Integer::intValue).toArray();

        this.res.gamewin = this.res.bet*this.res.multiple;

        this.res.allwin += this.res.gamewin+this.res.bounswin;
    }
}
